﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Diagnostics;
using LevelEditor.model.elements;

namespace LevelEditor.model.core
{
	class ParseXML
	{
		static private char[] delimiters = { ' ', '/', '\\', '.', ':', '\t' };

		static private bool readToRealNode(XmlTextReader xtr)
		{
			bool r = xtr.Read();

			String temp = xtr.Name.Trim();

			while (temp == "")
			{
				r = xtr.Read();
				temp = xtr.Name.Trim();
			}

			return r;
		}

		static public List<DoublePage> readXML(String url)
		{
			XmlTextReader xtr = new XmlTextReader(url);
			List<DoublePage> data;

			xtr.Read();

			if (xtr.Name == "xml")
				readToRealNode(xtr);

			switch (xtr.NodeType)
			{
				case XmlNodeType.Element:
					data = createClasses(xtr);
					break;

				case XmlNodeType.Text: // ?!
					Console.WriteLine("ERROR !! Text found !!");
					Console.ReadLine();
					Environment.Exit(-1);
					return null;

				default:
					Console.WriteLine("What the Heck is that Node ?!");
					Console.WriteLine(xtr.Name);
					Console.ReadLine();
					Environment.Exit(-1);
					return null;
			}

			xtr.Close();

			return data;

		}

		static public void writeXML(String url, List<DoublePage> dpList)
		{
			XmlWriter xtw = XmlWriter.Create(url);

			xtw.WriteStartDocument();
			xtw.WriteWhitespace("\n");

			xtw.WriteStartElement("level");
			xtw.WriteAttributeString("numberOfPage", dpList.Count.ToString());

			xtw.WriteWhitespace("\n\t");

			xtw.WriteStartElement("ressources");

			for (int h = 0; h < Library.usedAssetsList.Count; h++ )
			{
				xtw.WriteWhitespace("\n\t\t");
				xtw.WriteStartElement("object");
				xtw.WriteAttributeString("resId", h.ToString());
				xtw.WriteAttributeString("asset", Library.usedAssetsList[h] + ".xml");
				xtw.WriteFullEndElement();
			}

			xtw.WriteWhitespace("\n\t");
			xtw.WriteFullEndElement();

			for (int i = 0; i < dpList.Count; i++)
			{
				xtw.WriteWhitespace("\n\t");
				xtw.WriteStartElement("doublePage");
				xtw.WriteAttributeString("numberOfPage", i.ToString());

				for (int l = 0; l < dpList[i].pGameObjectsNb; l++) // Getter !!!
				{
					xtw.WriteWhitespace("\n\t\t");

					xtw.WriteStartElement("object");
					xtw.WriteAttributeString("type", dpList[i].pGameObjectsList[l].type);
					xtw.WriteAttributeString("resId", dpList[i].pGameObjectsList[l].resId.ToString());
					xtw.WriteAttributeString("id", l.ToString());
					xtw.WriteAttributeString("editName", dpList[i].pGameObjectsList[l].name);
					xtw.WriteAttributeString("positionX", dpList[i].pGameObjectsList[l].x.ToString());
					xtw.WriteAttributeString("positionY", dpList[i].pGameObjectsList[l].y.ToString());
					xtw.WriteAttributeString("scaleX", dpList[i].pGameObjectsList[l].scaleX.ToString());
					xtw.WriteAttributeString("scaleY", dpList[i].pGameObjectsList[l].scaleY.ToString());
					xtw.WriteAttributeString("orientation", dpList[i].pGameObjectsList[l].orientationAngle.ToString());
					xtw.WriteAttributeString("activated", dpList[i].pGameObjectsList[l].isActive.ToString());
					xtw.WriteFullEndElement();
				}

				xtw.WriteWhitespace("\n\t");
				xtw.WriteFullEndElement();
			}

			xtw.WriteWhitespace("\n");

			xtw.WriteEndDocument();

			xtw.Close();
		}

		static private List<DoublePage> createClasses(XmlTextReader xtr)
		{
			List<DoublePage> data = new List<DoublePage>();

			switch (xtr.Name)
			{
				case "objectDefinition":
					data = createObjectDefinition(xtr);
					break;

				case "level":
					data = loadLevel(xtr);
					break;

				case "chapter":
					break;
			}

			return data;
		}

		static private List<DoublePage> createObjectDefinition(XmlTextReader xtr)
		{
			Dictionary<String, String> args = new Dictionary<String, String>();

			xtr.Read();

			while (xtr.Name != "objectDefinition" && xtr.NodeType != XmlNodeType.EndElement)
			{
				if (xtr.Name == "animation")
					createAnimation(xtr);
				else
				{
					while (xtr.MoveToNextAttribute())
					{
						args.Add(xtr.Name, xtr.Value);
					}
				}

				xtr.Read();
			}

			return null;
			/* TO DO : Check existence in Library first before add */
		}

		static private List<DoublePage> loadLevel(XmlTextReader xtr) // Return Double Page List
		{
			String tempString;

			List<DoublePage> data = new List<DoublePage>();

			xtr.MoveToNextAttribute();
			String numberOfPage = xtr.Value; // Get number of Pages

			xtr.MoveToElement(); // Return to Node (we never know)
			xtr.Read(); // Go to next Node

			while (xtr.Name != "level" && xtr.NodeType != XmlNodeType.EndElement)
			{
				switch (xtr.Name)
				{
					case "ressources":
						{
							xtr.Read(); // Go to objects

							while (!(xtr.Name == "ressources" && xtr.NodeType == XmlNodeType.EndElement))
							{
								if (xtr.NodeType != XmlNodeType.EndElement)
								{
									xtr.MoveToNextAttribute();
									xtr.MoveToNextAttribute();
									tempString = xtr.Value.Trim();

									if (tempString != "")
									{
										String[] tempS = tempString.Split(ParseXML.delimiters);

										tempString = tempS[tempS.Length - 2];

										Library.addUsedAsset(tempString); // Add Ressources in Library
									}

									xtr.MoveToElement();
								}
								xtr.Read();
							}
						}
						break;

					case "doublePage":
						data.Add(createDoublePage(xtr));
						break;
				}
				xtr.Read();
			}

			return data;
		}

		static private DoublePage createDoublePage(XmlTextReader xtr)
		{
			List<Dictionary<String, String>> args = new List<Dictionary<string, string>>();

			xtr.MoveToNextAttribute();
			String num = xtr.Value.Trim();

			xtr.MoveToElement(); // Return to Node (we never know)

			readToRealNode(xtr);

			while (!(xtr.Name == "doublePage" && xtr.NodeType == XmlNodeType.EndElement))
			{
				Dictionary<String, String> tempArgs = new Dictionary<String, String>();

				if (xtr.NodeType != XmlNodeType.EndElement)
				{
					while (xtr.MoveToNextAttribute())
					{
						String name = xtr.Name.Trim();
						String value = xtr.Value.Trim();

						if (name != "" && value != "")
							tempArgs.Add(name, value);
					}

					args.Add(tempArgs);
				}

				xtr.MoveToElement();
				readToRealNode(xtr);
			}

			DoublePage dp = new DoublePage();
			dp.pGameObjectsList = PGameObjectsFactory.createPGameObjectsList(args);

			return dp;
		}

		static private void createAnimation(XmlTextReader xtr)
		{
			xtr.Read();

			while(!(xtr.Name == "animation" && xtr.NodeType == XmlNodeType.EndElement))
			{
				xtr.Read();
			}

			xtr.Read();
		}


		#region Library
		static public Dictionary<String, String> readXMLLibrary(String url)
		{
			XmlTextReader xtr = new XmlTextReader(url);
			Dictionary<String, String> data;

			String [] temp = url.Split(ParseXML.delimiters);

			xtr.Read();

			if (xtr.Name == "xml")
				readToRealNode(xtr);

			switch (xtr.NodeType)
			{
				case XmlNodeType.Element:
					data = createObjectDefinitionLibrary(xtr);
					break;

				case XmlNodeType.Text: // ?!
					Console.WriteLine("ERROR !! Text found !!");
					Console.ReadLine();
					Environment.Exit(-1);
					return null;

				default:
					Console.WriteLine("What the Heck is that Node ?!");
					Console.ReadLine();
					Environment.Exit(-1);
					return null;
			}

			data.Add("filename", temp[temp.Length - 2]);

            xtr.Close();

			return data;

		}

		static private Dictionary<String, String> createObjectDefinitionLibrary(XmlTextReader xtr)
		{
			// Assert xtr.name == objectdefinition
			Debug.Assert(xtr.Name == "objectDefinition");

			Dictionary<String, String> args = new Dictionary<String, String>();

			readToRealNode(xtr);

			while (xtr.Name != "objectDefinition" && xtr.NodeType != XmlNodeType.EndElement)
			{
				if (xtr.Name == "animation")
					createAnimation(xtr);
				else
				{
					while (xtr.MoveToNextAttribute())
					{
						args.Add(xtr.Name, xtr.Value);
					}
				}

				readToRealNode(xtr);
			}

			return args;
		}
		#endregion
	}
}
